﻿using System;
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

namespace Jinndev {

    /// <summary>
    /// 对象池分组，包含一个预设物
    /// </summary>
    public class PoolGroup : MonoBehaviour {

        [Tooltip("对象池名称，使用预设路径")]
        public string poolName;
        [Tooltip("预设物")]
        public GameObject prefab;
        [Tooltip("初始化缓存数量")]
        public int init;
        [Tooltip("最大缓存数量")]
        public int max;
        [Tooltip("自增长数量")]
        public int increment;
        [Tooltip("销毁间隔时间")]
        public float destroyInterval;

        private float timer;

        public void Init(string poolName, GameObject prefab, int init, int max, int increment, float destroyInterval) {
            this.poolName = poolName;
            this.prefab = prefab;
            this.init = init;
            this.max = max;
            this.increment = increment;
            this.destroyInterval = destroyInterval;
        }

        public void CreateInit() {
            for (int i = 0; i < Mathf.Min(init, max); i++) {
                CreateCacheObj();
            }
        }

        public List<Action> GetCreateInitActions() {
            List<Action> list = new List<Action>();
            for (int i = 0; i < Mathf.Min(init, max); i++) {
                list.Add(CreateCacheObj);
            }
            return list;
        }

        //public async Task CreateInit() {
        //    for (int i = 0; i < Mathf.Min(init, max); i++) {
        //        Task task = new Task(CreateCacheObj);
        //        task.RunSynchronously();
        //        await task;
        //    }
        //}


        private void Update() {
            if (destroyInterval > 0) {
                timer += Time.unscaledDeltaTime;
                if (timer >= destroyInterval) {
                    timer = 0;

                    if (transform.childCount >= max) {
                        Destroy(transform.GetChild(0).gameObject);
                        return;
                    }
                }
            }
        }

        /// <summary>
        /// 实例化当前池中的预设，并挂载PoolItem组件用于标记和回收
        /// </summary>
        public GameObject Instantiate(Transform parent = null, bool worldPositionStays = false) {
            GameObject obj = null;
            if (transform.childCount > 0) {
                // 如果有缓存的对象，则从缓存中取得实例
                obj = transform.GetChild(transform.childCount - 1).gameObject;
                obj.transform.SetParent(parent, worldPositionStays);
                obj.SetActive(true);
            }
            else if (prefab != null) {
                // 如果没有缓存的对象，则实例化一个
                if (parent == null) {
                    obj = Instantiate(prefab);
                }
                else {
                    obj = Instantiate(prefab, parent, worldPositionStays);
                }
            }
            CommonUtil.GetOrAddComponent<PoolItem>(obj).poolName = poolName;
            return obj;
        }

        /// <summary>
        /// 实例化一个预设并放入池中
        /// </summary>
        private void CreateCacheObj() {
            GameObject obj = Instantiate(prefab, transform, false);
            obj.SetActive(false);
            obj.AddComponent<PoolItem>().poolName = poolName;
        }

        /// <summary>
        /// 回收目标物体
        /// </summary>
        public void Recycle(GameObject obj) {
            if (destroyInterval <= 0) {
                if (transform.childCount >= max) {
                    // 超过最大容量，直接销毁
                    Destroy(obj);
                    return;
                }
            }
            // 回收
            // 尝试执行自定义回收逻辑
            IRecyclable recyclable = obj.GetComponent<IRecyclable>();
            try {
                recyclable?.OnRecycle();
            }
            catch (Exception e) {
                Debug.LogException(e);
            }
            // 移动到对象池中
            obj.SetActive(false);
            obj.transform.SetParent(transform, false);
        }

        /// <summary>
        /// 名称是否匹配此对象池
        /// </summary>
        public bool Match(string name) {
            return prefab != null && !string.IsNullOrWhiteSpace(poolName) && (poolName.Equals(name) || name.Equals(prefab.name));
        }

        /// <summary>
        /// 预设是否匹配此对象池
        /// </summary>
        public bool Match(GameObject prefab) {
            return this.prefab != null && this.prefab == prefab;
        }

#if UNITY_EDITOR
        public void SetupByPrefab() {
            if (prefab == null) {
                return;
            }
            string assetPath = AssetDatabase.GetAssetPath(prefab);
            if (assetPath.IndexOf("Resources/") != -1) {
                poolName = CommonUtil.SubStringFromTo(assetPath, "Resources/", ".");
            }
            else {
                poolName = CommonUtil.SubStringFromTo(assetPath, "Assets/", ".");
            }
            gameObject.name = prefab.name;
        }
#endif

    }

#if UNITY_EDITOR
    [CustomEditor(typeof(PoolGroup), true)]
    public class PoolGroupEditor : Editor {

        private PoolGroup poolGroup;

        private void OnEnable() {
            poolGroup = target as PoolGroup;
        }

        public override void OnInspectorGUI() {
            if (poolGroup.prefab != null && GUILayout.Button("自动更改名称")) {
                poolGroup.SetupByPrefab();
            }
            DrawDefaultInspector();
        }

    }
#endif


}
